#include <iostream>
#include <conio.h>
#include <time.h>
#include "Snake.h"

volatile int global_adress_of_food;

SNAKE_handle::SNAKE_handle():
  last_direction ( RIGHT )
{
#ifdef _DEBUG
  logfile.log << "\n\n\n==========NEW SESSION==========\n\n";
#endif // _DEBUG
	memset ( snake_body, ' ', MAX_SNAKE_LENGTH );
	instanceCount++;
}

void SNAKE_handle::set_snake ( char Snake_field[][VERTICAL] )
{
	//Set the snake in the middle of the field
	Snake_field [HORIZONTAL/2]	[VERTICAL/2 + 1]	= 'X';
	Snake_field [HORIZONTAL/2]	[VERTICAL/2]		= '#';
	Snake_field [HORIZONTAL/2]	[VERTICAL/2 - 1]	= '#';
	Snake_field [HORIZONTAL/2]	[VERTICAL/2 - 2]	= '#';
	/*
	* load the adress of the Snake-body in a array.
	* This array has saved the body elements in the right order.
	*/
	snake_body[0] = &Snake_field [HORIZONTAL/2]	[VERTICAL/2 + 1];
	snake_body[1] = &Snake_field [HORIZONTAL/2]	[VERTICAL/2];
	snake_body[2] = &Snake_field [HORIZONTAL/2]	[VERTICAL/2 - 1];
	snake_body[3] = &Snake_field [HORIZONTAL/2]	[VERTICAL/2 - 2];

	body_elements = 4;

	set_food ( Snake_field );

	//position of the head
	head.hight = HORIZONTAL/2;
	head.wide = VERTICAL/2 + 1;
}

/*
* Funktion for Printing out the Snake
* INPUT: Pointer to the field from the main funktion
* Return: --
*/
void SNAKE_handle::show ( char Snake_field[][VERTICAL] )
{
	int i = 0;
	int j = 0;
	while ( i < HORIZONTAL )
	{
		while ( j < VERTICAL )
		{
			std::cout << Snake_field [i] [j++];
		}
		std::cout << std::endl;
		j=0;
		i++;
	}
}

void SNAKE_handle::snake_move ( char Snake_field[][VERTICAL] )
{
	int body = body_elements;
	if ( feeding ( Snake_field ) )
	{
		*snake_body	[body-1] = ' ';
	}
	else 
	{
		body++;
	}
	while ( body-1 )
	{
		Snake_field	[head.hight]	[head.wide] = '#';
		snake_body	[body-1] = snake_body	[body-2];
		body--;
	}
	switch ( last_direction )
	{
		case RIGHT: 
		{
			if ( head.wide+1 >= VERTICAL )
			{
				head.wide = 0;
			}
			else
			{
				head.wide++;
			}
			Snake_field	[head.hight]	[head.wide] = 'X';
			break;
		}
		case HIGH:
		{
			if ( !(head.hight) )
			{
				head.hight = HORIZONTAL-1;
			}
			else
			{
				head.hight--;
			}
			Snake_field	[head.hight]	[head.wide] = 'X';
			break;
		}
		case DOWN:
		{
			if ( head.hight + 1 >= HORIZONTAL )
			{
				head.hight = 0;
			}
			else
			{
				head.hight++;
			}
			Snake_field	[head.hight]	[head.wide] = 'X';
			break;
		}
		case LEFT:
		{
			if ( !head.wide )
			{
				head.wide = VERTICAL-1;
			}
			else
			{
				head.wide--;
			}
			Snake_field	[head.hight]	[head.wide] = 'X';
			break;
		}
	}
	snake_body [0] = &Snake_field	[head.hight]	[head.wide];
}

void SNAKE_handle::User_input ( void )
{
	char input = 0;
	if ( _kbhit () )
	{
		input = _getch ();
		switch ( input ) 
		{
			case 'w': 
			{
				if ( last_direction != DOWN )
					last_direction = HIGH; 
				break;
			}
			case 'a':
			{
				if ( last_direction != RIGHT )
					last_direction = LEFT; 
				break;
			}
			case 's': 
			{
				if ( last_direction != HIGH )
					last_direction = DOWN; 
				break;
			}
			case 'd': 
			{
				if ( last_direction != LEFT )
					last_direction = RIGHT; 
				break;
			}
		}
	}	
}

bool SNAKE_handle::feeding( char Snake_field[][VERTICAL] )
{
	bool check_feeding = true;
#ifdef _DEBUG
  logfile.out_number_with_text ( "Check if eaten. Adress of the head of the snake", (int)&Snake_field	[head.hight]	[head.wide] );
  logfile.log << std::endl;
  if ( global_adress_of_food == (int)&Snake_field	[head.hight]	[head.wide] )
  {
    logfile.out_number_with_text ( "\n\nDIRECTION", last_direction );
    logfile.log << std::endl << std::endl;
    //exit ( 0 );
  }
  logfile.out_number_with_text ( "Check if eaten. Adress of the head of the snake", (int)&Snake_field	[head.hight]	[head.wide] );
  logfile.log << std::endl;
#endif //_DEBUG
  if ( global_adress_of_food == (int)&Snake_field	[head.hight]	[head.wide] )
  {
    if_fooding ( Snake_field );
    check_feeding = false;
  }
	switch ( last_direction )
	{
		case RIGHT:
		{
			if ( &Snake_field	[head.hight]	[head.wide+1] == food && head.wide + 1 < VERTICAL )
			{
#ifdef _DEBUG
        logfile.out_number_with_text ( "\nIf the Snake comes from the Right, the adress of the food is", (int) &Snake_field	[head.hight]	[head.wide+1] );
#endif //_DEBUG
				if_fooding ( Snake_field );
				check_feeding = false;
			}
			break;
		}
		case LEFT:
		{
			if ( &Snake_field [head.hight] [ head.wide-1 ] == food )
			{
#ifdef _DEBUG
        logfile.out_number_with_text ( "\nIf the Snake comes from the Left, the adress of the food is", (int) (snake_body[0]) );
#endif //_DEBUG
				if_fooding ( Snake_field );
				check_feeding = false;
			}
			break;
		}
		case DOWN:
		{
			if (  &Snake_field	[head.hight+1]	[head.wide] == food && head.hight + 1 < HORIZONTAL )
			{
#ifdef _DEBUG
        logfile.out_number_with_text ( "\nIf the Snake comes from the Down, the adress of the food is", (int) &Snake_field	[head.hight+1]	[head.wide] );
#endif //_DEBUG
				if_fooding ( Snake_field );
				check_feeding = false;
			}
			break;
		}
		case HIGH:
		{ 
			if (  &Snake_field	[head.hight-1]	[head.wide] == food )
			{
#ifdef _DEBUG
        logfile.out_number_with_text ( "\nIf the Snake comes from the High, the adress of the food is", (int) &Snake_field	[head.hight-1]	[head.wide] );
#endif //_DEBUG
				if_fooding ( Snake_field );
				check_feeding = false;
			}
			break;
		}
	}
	return check_feeding;
}

void SNAKE_handle::set_food(char Snake_field[][VERTICAL])
{
	int body = body_elements;
	struct coordinates next_food = {0};
	srand( (unsigned int) time ( 0 ) );
	do
	{
		next_food.hight = rand() % HORIZONTAL;
		next_food.wide	= rand() % VERTICAL;
#ifdef _DEBUG
    static int index = 0;
    logfile.out_number_with_text ( "LINE-NUMBER", __LINE__ );
    logfile.out_number_with_text ( "\nafter passage number", index++ );
		logfile.out_number_with_text ( "\tnext_food.high", next_food.hight );
		logfile.out_number_with_text ( "\tnext_food.wide", next_food.wide );
		logfile.out_number_with_text ( "\tAdress of the food-position", (int) &Snake_field	[next_food.hight]	[next_food.wide] );

#endif //_DEBUG
		global_adress_of_food = (int) &Snake_field	[next_food.hight]	[next_food.wide];
		food = &Snake_field	[next_food.hight]	[next_food.wide];
	}
	while ( check_food ( body, Snake_field, next_food ) );
	*food = 'O';
}

void SNAKE_handle::if_fooding(char Snake_field[][VERTICAL])
{
	body_elements++;
	snake_body	[ body_elements - 1 ] = food;
	*snake_body [ body_elements - 1 ] = '#';
	set_food ( Snake_field );
}


bool SNAKE_handle::check_food(int body, char Snake_field[][VERTICAL], struct coordinates next_food)
{
	bool if_food_is_at_snake = false;
	while ( body )
	{
#ifdef _DEBUG
    for ( int i = 0; i < HORIZONTAL; i++ )
    {
      for ( int j = 0; j < VERTICAL; j++ )
      {
        if ( &Snake_field [i] [j] == snake_body [body] )
        {
          logfile.log << "\nPosition of snake:\t";
          logfile.out_number_with_text ( "Length coordinate", i );
          logfile.out_number_with_text ( "Wide coordinate", j );
        }
      }
    }
    logfile.out_number_with_text ( "Adress of the Body-element", (int) snake_body [body] );
    logfile.out_number_with_text ( "Size of body", body );
#endif //_DEBUG
		if ( food	== snake_body	[--body] )
		{
			if_food_is_at_snake = true;
			break;
		}
	}
	if ( food == &Snake_field [head.hight] [head.wide] )
	{
	  if_food_is_at_snake = true;
#ifdef _DEBUG
    logfile.log << "Head is equal with the food. Adress of head: " << (int) Snake_field [head.hight] [head.wide] << std::endl;
#endif _DEBUG
	}
#ifdef _DEBUG
  logfile.log << std::endl;
#endif //_DEBUG
	return if_food_is_at_snake;
}

bool SNAKE_handle::self_eat(char Snake_field[][VERTICAL])
{
	bool eat_not_body = true;
	int body = body_elements;
	while ( body - 1 )
	{
		if ( &Snake_field	[head.hight]	[head.wide] == snake_body [body--] )
		{
			eat_not_body = false;
			break;
		}
	}
	return eat_not_body;
}

int SNAKE_handle::instanceCount = 0;